package com.bluerox.updating;

import java.io.File;
import java.util.Iterator;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;

/** 
* 移动文件类<br><br>
* Example:<br><br>
* Entity entity = new Entity();<br>
* entity.setTitle("Race");<br>
* entity.setVersion("1.0.0");<br>
* ...<br><br>
* String statusFileName = "/home/lijianbo/test/Race/temp/status/1234567890abcdef.xml";<br>
* Document statusDoc = XML.parseFile(statusFileName);<br><br>
* String levelFileName = "/home/lijianbo/test/Race/temp/Race_1_0_0_level_1.xml"<br>
* Element rootElement = XML.parseFile(levelFileName).getRootElement();<br>
* 
* MoveFiles mf = new MoveFiles(entity, statusDoc, rootElement);<br><br>
* try {<br>
* 	String from = "/home/lijianbo/test/Race/temp/start.bin";<br>
* 	String to = "/home/lijainbo/test/Race/start.bin";<br>
* 	mf.move(from, to);<br>
* } catch (Exception e) {<br>
* 	e.printStackTrace();<br>
* }<br>
* @author 李建波 
*/
public class MoveFiles {
	
	private Entity entity = null;
	private Document statusDoc = null;
	private Element rootElement = null;
	private String levelValue = null;

	/**
	 * 构造函数
	 * @param entity 程序的实体对象
	 * @param statusDoc 状态文件
	 * @param rootElement 需要移动的文件目录的根节点
	 */
	public MoveFiles(Entity entity, Document statusDoc, Element rootElement){
		this.entity = entity;
		this.statusDoc = statusDoc;
		this.rootElement = rootElement;
	}
	
	/**
	 * 构造函数，这个构造函数多加了索引文件中的级别值
	 * @param entity
	 * @param statusDoc
	 * @param rootElement
	 * @param levelValue
	 */
	public MoveFiles(Entity entity,Document statusDoc,Element rootElement,String levelValue) {
		this.entity = entity;
		this.statusDoc = statusDoc;
		this.rootElement = rootElement;
		this.levelValue = levelValue;
	}
	
	
	/**
	 * 移动文件目录到指定位置
	 * @param from 原目录位置
	 * @param to 指定位置
	 * @throws Exception
	 */
	public void move(String from, String to) throws Exception {
		try {
			File dir = new File(from);
			File[] files = dir.listFiles();
			
			if(files.length == 0) {
				System.out.println("目标文件夹中没有任何文件");
				return;
			}
			
			File moveDir = new File(to);
			
			System.out.println("创建路径：" + to);
			if (!moveDir.exists()) {
				moveDir.mkdirs();
			}
			
			//循环递归的方式移动文件
			for (int i = 0; i < files.length; i++) {
				if (files[i].isDirectory()) {
					move(files[i].getPath(), to + File.separator + files[i].getName());
				}
				File moveFile = new File(moveDir.getPath() + File.separator + files[i].getName());
				
				System.out.println("移动文件：" + moveFile.getPath());
				files[i].renameTo(moveFile);
				
				if(!files[i].isDirectory()){
					updateStatusFile(files[i].getPath(), files[i].getName());
				}
				//删除临时文件
				files[i].delete();
			}
		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
	 * 这个方法也是移动文件，主要的不同是，这个方法内部调用的是重载了的updateStatusFile方法，
	 * @param from 源文件夹位置
	 * @param to 目的文件夹位置
	 * @throws Exception
	 */
	public void moveWithLevelValue(String from ,String to) throws Exception {
		try {
			File dir = new File(from);
			File[] files = dir.listFiles();
			
			if(files.length == 0) {
				System.out.println("目标文件夹中没有任何文件");
				return;
			}
			
			File moveDir = new File(to);
			
			System.out.println("创建路径：" + to);
			if (!moveDir.exists()) {
				moveDir.mkdirs();
			}
			
			//循环递归的方式移动文件
			for (int i = 0; i < files.length; i++) {
				if (files[i].isDirectory()) {
					moveWithLevelValue(files[i].getPath(), to + File.separator + files[i].getName());
				}
				File moveFile = new File(moveDir.getPath() + File.separator + files[i].getName());
				
				System.out.println("移动文件：" + moveFile.getPath());
				files[i].renameTo(moveFile);
				
				if(!files[i].isDirectory()){
					updateStatusFile(files[i].getPath(), files[i].getName(),this.levelValue);
				}
				
				//删除临时文件
				files[i].delete();
			}
		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
	 * 更新状态文件，标记已移动的文件状态为finish
	 * @param path 文件的路径 //临时文件夹下的路径！
	 * @param name 文件名称
	 */
	@SuppressWarnings("unchecked")
	private void updateStatusFile(String path, String name){
		//首先根据文件目录结构到索引文件中取得相应文件的MD5码
		//Modify by kiven:String[] folders = path.split("/"); 对这段代码的修改如下所示，修改成这样更加通用
		String[] folders = path.split(File.separator);
		
		String md5 = "";
		int tempPathLevel = this.entity.getTempPath().split(File.separator).length + 1;  //为什么要加1？为了省去root的目录也就是Race目录，这样就可以直接
		
		Element objElement = this.rootElement;
		for(int i=tempPathLevel;i<folders.length;i++){
			List<Element> elements = objElement.getChildren("directory");
			for(int j=0;j<elements.size();j++){
				if(elements.get(j).getAttributeValue("name").equals(folders[i])){
					objElement = elements.get(j);
					break;
				}
			}
		}
		
		List<Element> files = objElement.getChildren("file");
		for(int i=0;i<files.size();i++){
			if(files.get(i).getAttributeValue("name").equals(name)){
				md5 = files.get(i).getChildText("md5");
				break;
			}
		}

		//根据MD5码修改状态文件中对应文件的状态并保存
		XML xml = new XML(this.entity);
		this.statusDoc.getRootElement().getChild("md5-" + md5).setAttribute("status","finish");
		xml.save(this.statusDoc, this.entity.getTempStatusPath() + File.separator + this.entity.getStatusFileName());
	}
	
	/**
	 * 更新状态文件，标记已经移动的状态文件为finish,但是这个方法是重载无指定状态文件的级别值的方法
	 * @param path
	 * @param name
	 * @param levelValue
	 */
	@SuppressWarnings("unchecked")
	private void updateStatusFile(String path, String name,String levelValue){
		//首先根据文件目录结构到索引文件中取得相应文件的MD5码
		//Modify by kiven:String[] folders = path.split("/"); 对这段代码的修改如下所示，修改成这样更加通用
		String[] folders = path.split(File.separator);
		
		String md5 = "";
		int tempPathLevel = this.entity.getTempPath().split(File.separator).length + 1;  
		
		Element objElement = this.rootElement;
		for(int i=tempPathLevel;i<folders.length;i++){
			List<Element> elements = objElement.getChildren("directory");
			for(int j=0;j<elements.size();j++){
				if(elements.get(j).getAttributeValue("name").equals(folders[i])){
					objElement = elements.get(j);
					break;
				}
			}
		}
		
		List<Element> files = objElement.getChildren("file");
		for(int i=0;i<files.size();i++){
			/*
			 * equals()比较的条件要注意，由于在移动操作中所获得的文件名是解压缩的文件名，然而在索引文件file节点中的文件名是.zip结尾的
			 * 主索引文件中file节点的文件名是：aaa.bin.zip
			 * 临时文件夹中解压缩的文件的名字是：aaa.bin
			 * 在比较文件名的时候一定要先把文件名组织正确
			 * 所以在条件比较是有两种方法：
			 * 方法1：
			 * files.get(i).getAttributeValue("name")进行切割，将.zip去掉
			 * 方法2：
			 * 如下
			 */
			if(files.get(i).getAttributeValue("name").equals(name + Entity.ZIP_EXT)){
				md5 = files.get(i).getChildText("md5");
				break;
			}
		}
		
		//根据MD5码修改状态文件中对应文件的状态并保存
		XML xml = new XML(this.entity);
		
		//根据级别值找到相应的级别子节点下
		List list = this.statusDoc.getRootElement().getChildren("level");
		Iterator iter = list.iterator();
		
		Element element = null;
		while(iter.hasNext()) {
			element = (Element)iter.next();
			if(element.getAttributeValue("value").equals(levelValue)) {
				//将已经移动到正确位置的文件的状态变为finish
				element.getChild("md5-" + md5).setAttribute("status","finish");
				xml.save(this.statusDoc, this.entity.getTempStatusPath() + File.separator + this.entity.getStatusFileName());
			}
		}
		
	}
	
	
}
